﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Castle.DynamicProxy;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using Castle.Windsor.Installer;
using Castle.Windsor.Proxy;

namespace WJP.Dependency
{
    /// <summary>
    /// 这个类用于直接执行依赖性注入任务。
    /// </summary>
    public class IocManager : IIocManager
    {
        /// <summary>
        /// Castle Windsor Container容器的引用
        /// </summary>
        public IWindsorContainer IocContainer { get; private set; }

        /// <summary>
        /// 单例
        /// </summary>
        public static IocManager Instance { get; private set; }

        /// <summary>
        /// 约定注册依赖项列表
        /// </summary>
        private readonly List<IConventionalDependencyRegistrar> _conventionalRegistrars;

        /// <summary>
        /// ProxyGenerator的单例
        /// <para>根据Castle.Core文档说明，使用ProxyGenerator单例可以避免内存和性能问题</para>
        /// <para>点击下面的链接了解更多细节：</para>
        /// <a href="https://github.com/castleproject/Core/blob/master/docs/dynamicproxy.md">Castle.Core文档</a>
        /// </summary>
        private static readonly ProxyGenerator ProxyGeneratorInstance = new ProxyGenerator();

        static IocManager()
        {
            Instance = new IocManager();
        }

        public IocManager()
        {
            IocContainer = CreateContainer();
            _conventionalRegistrars = new List<IConventionalDependencyRegistrar>();

            // 注册自身
            IocContainer.Register(
                Component.For<IocManager, IIocManager, IIocRegistrar, IIocResolver>().UsingFactoryMethod(() => this)
                );
        }

        protected virtual IWindsorContainer CreateContainer()
        {
            return new WindsorContainer(new DefaultProxyFactory(ProxyGeneratorInstance));
        }

        #region Register

        /// <summary>
        /// 添加约定注册提供者，IOC容器会根据约定注册类注册程序集所有符合约定的对象，实现快速注册
        /// <para>比如<see cref="BasicConventionalRegistrar"/>会注册所有实现了IInterceptor、ITransientDependency和ISingletonDependency的对象</para>
        /// </summary>
        /// <param name="registrar">依赖注册</param>
        public void AddConventionalRegistrar(IConventionalDependencyRegistrar registrar)
        {
            _conventionalRegistrars.Add(registrar);
        }

        /// <summary>
        /// 添加要用所有约定注册进行注册的程序集
        /// </summary>
        /// <param name="assembly">要用于注册的程序集</param>
        public void RegisterAssemblyByConvention(Assembly assembly)
        {
            RegisterAssemblyByConvention(assembly, new ConventionalRegistrationConfig());
        }

        /// <summary>
        /// 添加要用所有约定注册进行注册的程序集
        /// <para>一般在执行插件初始化的时候注册程序集</para>
        /// </summary>
        /// <param name="assembly">要用于注册的程序集</param>
        /// <param name="config">约定注册配置</param>
        public void RegisterAssemblyByConvention(Assembly assembly, ConventionalRegistrationConfig config)
        {
            var context = new ConventionalRegistrationContext(assembly, this, config);

            foreach (var registerer in _conventionalRegistrars)
            {
                registerer.RegisterAssembly(context);
            }

            if (config.InstallInstallers)
            {
                IocContainer.Install(FromAssembly.Instance(assembly));
            }
        }

        /// <summary>
        /// 将类型注册为自注册
        /// </summary>
        /// <typeparam name="T">类的类型</typeparam>
        /// <param name="lifeStyle">这个类型的生命周期，默认为单例模式</param>
        public void Register<T>(DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton) where T : class
        {
            IocContainer.Register(ApplyLifestyle(Component.For<T>(), lifeStyle));
        }

        /// <summary>
        /// 将类型注册为自注册
        /// </summary>
        /// <typeparam name="T">类的类型</typeparam>
        /// <param name="key">组件的名称</param>
        /// <param name="lifeStyle">这个类型的生命周期，默认为单例模式</param>
        public void Register<T>(string key, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton) where T : class
        {
            IocContainer.Register(ApplyLifestyle(Component.For<T>(), lifeStyle).Named(key));
        }

        /// <summary>
        /// 将类型注册为自注册
        /// </summary>
        /// <param name="type">类的类型</param>
        /// <param name="lifeStyle">这个类型的生命周期，默认为单例模式</param>
        public void Register(Type type, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton)
        {
            IocContainer.Register(ApplyLifestyle(Component.For(type), lifeStyle));
        }

        /// <summary>
        /// 将类型注册为自注册
        /// </summary>
        /// <param name="key"></param>
        /// <param name="type">类的类型</param>
        /// <param name="lifeStyle">这个类型的生命周期，默认为单例模式</param>
        public void Register(string key, Type type, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton)
        {
            IocContainer.Register(ApplyLifestyle(Component.For(type), lifeStyle));
        }

        /// <summary>
        /// 向类型的实现注册类型
        /// </summary>
        /// <typeparam name="TType">注册类型</typeparam>
        /// <typeparam name="TImpl">类型<typeparamref name="TType"/>的实现类</typeparam>
        /// <param name="lifeStyle">这个类型的生命周期，默认为单例模式</param>
        public void Register<TType, TImpl>(DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton)
            where TType : class
            where TImpl : class, TType
        {
            IocContainer.Register(ApplyLifestyle(Component.For<TType, TImpl>().ImplementedBy<TImpl>(), lifeStyle));
        }

        /// <summary>
        /// 向类型的实现注册类型
        /// </summary>
        /// <typeparam name="TType">注册类型</typeparam>
        /// <typeparam name="TImpl">类型<typeparamref name="TType"/>的实现类</typeparam>
        /// <param name="key"></param>
        /// <param name="lifeStyle">这个类型的生命周期，默认为单例模式</param>
        public void Register<TType, TImpl>(string key, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton)
            where TType : class
            where TImpl : class, TType
        {
            IocContainer.Register(ApplyLifestyle(Component.For<TType, TImpl>().ImplementedBy<TImpl>(), lifeStyle).Named(key));
        }

        /// <summary>
        /// 向类型的实现注册类型
        /// </summary>
        /// <param name="type">注册类型</param>
        /// <param name="impl">类型<paramref name="type"/>的实现类</param>
        /// <param name="lifeStyle">这个类型的生命周期，默认为单例模式</param>
        public void Register(Type type, Type impl, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton)
        {
            IocContainer.Register(ApplyLifestyle(Component.For(type, impl).ImplementedBy(impl), lifeStyle));
        }

        /// <summary>
        /// 向类型的实现注册类型
        /// </summary>
        /// <param name="key"></param>
        /// <param name="type">注册类型</param>
        /// <param name="impl">类型<paramref name="type"/>的实现类</param>
        /// <param name="lifeStyle">这个类型的生命周期，默认为单例模式</param>
        public void Register(string key, Type type, Type impl, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton)
        {
            IocContainer.Register(ApplyLifestyle(Component.For(type, impl).ImplementedBy(impl), lifeStyle));
        }

        /// <summary>
        /// 检查之前是否注册了给定的类型
        /// </summary>
        /// <typeparam name="T">要检查的类型</typeparam>
        /// <returns></returns>
        public bool IsRegistered<T>()
        {
            return IocContainer.Kernel.HasComponent(typeof(T));
        }

        /// <summary>
        /// 检查之前是否注册了给定的类型
        /// </summary>
        /// <param name="type">要检查的类型</param>
        /// <returns></returns>
        public bool IsRegistered(Type type)
        {
            return IocContainer.Kernel.HasComponent(type);
        }

        #endregion

        #region Resolve

        /// <summary>
        /// 从IOC容器获取一个对象
        /// <para>返回对象必须在使用后释放，请看<see cref="Release(object)"/></para>
        /// </summary>
        /// <typeparam name="T">要得到的对象的类型</typeparam>
        /// <returns>对象实例</returns>
        public T Resolve<T>()
        {
            return IocContainer.Resolve<T>();
        }

        /// <summary>
        /// 从IOC容器获取一个对象
        /// <para>返回对象必须在使用后释放，请看<see cref="Release(object)"/></para>
        /// </summary>
        /// <param name="type">要得到的对象的类型</param>
        /// <returns>对象实例</returns>
        public object Resolve(Type type)
        {
            return IocContainer.Resolve(type);
        }

        /// <summary>
        /// 获取给定类型的所有实现
        /// <para>返回对象必须在使用后释放，请看<see cref="Release(object)"/></para>
        /// </summary>
        /// <typeparam name="T">要解析的对象类型</typeparam>
        /// <returns>对象实例</returns>
        public T[] ResolveAll<T>()
        {
            return IocContainer.ResolveAll<T>();
        }

        /// <summary>
        /// 获取给定类型的所有实现
        /// <para>返回对象必须在使用后释放，请看<see cref="Release(object)"/></para>
        /// </summary>
        /// <param name="type">要解析的对象类型</param>
        /// <returns>对象实例</returns>
        public Array ResolveAll(Type type)
        {
            return IocContainer.ResolveAll(type);
        }

        public object Resolve(string key, Type service, Arguments arguments)
        {
            return IocContainer.Resolve(key, service, arguments);
        }

        public T Resolve<T>(string key, Arguments arguments)
        {
            return IocContainer.Resolve<T>(key, arguments);
        }

        public T Resolve<T>(Arguments arguments)
        {
            return IocContainer.Resolve<T>(arguments);
        }

        public object Resolve(string key, Type service)
        {
            return IocContainer.Resolve(key, service);
        }

        public T Resolve<T>(string key)
        {
            return IocContainer.Resolve<T>(key);
        }

        public object Resolve(Type service, Arguments arguments)
        {
            return IocContainer.Resolve(service, arguments);
        }

        public Array ResolveAll(Type service, Arguments arguments)
        {
            return IocContainer.ResolveAll(service, arguments);
        }

        public T[] ResolveAll<T>(Arguments arguments)
        {
            return IocContainer.ResolveAll<T>(arguments);
        }

        #endregion

        /// <summary>
        /// 释放一个解析依赖对象。
        /// </summary>
        /// <param name="obj">要释放的对象</param>
        public void Release(object obj)
        {
            IocContainer.Release(obj);
        }

        /// <inheritdoc/>
        public void Dispose()
        {
            IocContainer.Dispose();
        }

        private static ComponentRegistration<T> ApplyLifestyle<T>(ComponentRegistration<T> registration, DependencyLifeStyle lifeStyle)
            where T : class
        {
            switch (lifeStyle)
            {
                case DependencyLifeStyle.Transient:
                    return registration.LifestyleTransient();
                case DependencyLifeStyle.Singleton:
                    return registration.LifestyleSingleton();
                default:
                    return registration;
            }
        }
    }
}
